package com.tlgen.zero.utils;

import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.tlgen.orm.utils.SpringUtils;
import com.tlgen.zero.model.RequestMappingClasses;
import com.tlgen.zero.model.RequestMethodAndUrl;
import org.springframework.core.env.Environment;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.tlgen.zero.utils.AnnotationUtils.getRequestMappingClassesWithAnnotation;

public class ScanUtils {

    /**
     * 获取根目录下包含指定注解下的类
     *
     * @param annotationType
     * @return
     */
    public static List<String> getClassesWithAnnotation(Class<? extends Annotation> annotationType) {
        List<String> classNames = new ArrayList<>();
        String localDirectory = System.getProperty("user.dir") + "\\src\\main\\java";
        File filePath = new File(localDirectory);
        List<File> aFiles = new ArrayList<>();
        getAllFile(filePath, aFiles);
        aFiles = aFiles.stream().filter(x -> x.getName().contains(".java")).collect(Collectors.toList());
        try {
            for (File aFile : aFiles) {
                String absolutePath = aFile.getAbsolutePath();
                String className = absolutePath
                        .substring(absolutePath.indexOf("\\java") + 6, absolutePath.lastIndexOf(".java"))
                        .replaceAll("\\\\", ".");
                Class<?> clazz = Class.forName(className);
                Annotation[] annotations = clazz.getAnnotationsByType(annotationType);
                if (annotations.length > 0) {
                    classNames.add(clazz.getName());
                }
            }
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        return classNames;
    }

    /**
     * 获取根目录下方法上包含指定注解下的类
     *
     * @param annotationType
     * @return
     */
    public static List<String> getClassesMethodWithAnnotation(Class<? extends Annotation> annotationType) {
        List<String> classNames = new ArrayList<>();
        String localDirectory = System.getProperty("user.dir") + "\\src\\main\\java";
        File filePath = new File(localDirectory);
        List<File> aFiles = new ArrayList<>();
        getAllFile(filePath, aFiles);
        aFiles = aFiles.stream().filter(x -> x.getName().contains(".java")).collect(Collectors.toList());
        try {
            for (File aFile : aFiles) {
                String absolutePath = aFile.getAbsolutePath();
                String className = absolutePath
                        .substring(absolutePath.indexOf("\\java") + 6, absolutePath.lastIndexOf(".java"))
                        .replaceAll("\\\\", ".");
                Class<?> clazz = Class.forName(className);
                for (Method declaredMethod : clazz.getDeclaredMethods()) {
                    Annotation annotation = declaredMethod.getAnnotation(annotationType);
                    if (Objects.nonNull(annotation)) {
                        classNames.add(clazz.getName());
                    }
                }
            }
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        return classNames;
    }

    /**
     * 获取根目录下指定接口的实现类
     *
     * @param interfaceClass
     * @return
     */
    public static List<String> getImplClassesByInterfaceClass(Class<?> interfaceClass) {
        List<String> classNames = new ArrayList<>();
        String localDirectory = System.getProperty("user.dir") + "\\src\\main\\java";
        File filePath = new File(localDirectory);
        List<File> aFiles = new ArrayList<>();
        getAllFile(filePath, aFiles);
        aFiles = aFiles.stream().filter(x -> x.getName().contains(".java")).collect(Collectors.toList());
        for (File aFile : aFiles) {
            String absolutePath = aFile.getAbsolutePath();
            String className = absolutePath
                    .substring(absolutePath.indexOf("\\java") + 6, absolutePath.lastIndexOf(".java"))
                    .replaceAll("\\\\", ".");
            String text = FileUtils.readFile(new File(absolutePath));
            if (StrUtil.isNotBlank(text)) {
                text = text.replace("\n", "").replaceAll("\\s", "");
                if (text.contains("@Service") && !text.contains("//publicclass") && text.trim().contains("implements" + StringUtils.getSimpleClassName(interfaceClass.getName()))) {
                    classNames.add(className);
                }
            }
        }
        return classNames;
    }

    /**
     * 获取全部扩展定义的接口
     *
     * @return
     */
    public static List<RequestMethodAndUrl> getExtendApiUrls() {
        List<RequestMethodAndUrl> requestMethodAndUrls = Lists.newArrayList();
        List<RequestMappingClasses> RequestMappingClassesWithAnnotation = getRequestMappingClassesWithAnnotation();
        for (RequestMappingClasses RequestMappingClasses : RequestMappingClassesWithAnnotation) {
            requestMethodAndUrls.addAll(RequestMappingClasses.getRequestMethodAndUrls());
        }
        return requestMethodAndUrls;
    }

    /**
     * 获取项目名称
     *
     * @return
     */
    public static String getApplicationName() {
        Environment environment = SpringUtils.getBean(Environment.class);
        return environment.getProperty("spring.application.name");
    }

    /**
     * 当前目录下的所有文件-不包括目录-递归方法
     *
     * @param fileList
     */
    private static void getAllFile(File file, List<File> fileList) {
        if (file.isDirectory()) {
            for (File listFile : Objects.requireNonNull(file.listFiles())) {
                getAllFile(listFile, fileList);
            }
        } else {
            fileList.add(file);
        }
    }

}
